package com.le.tester.nioplan.server;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

/**
 * createTime：2021/12/1 13:45
 * description：nio服务器端
 */
public class NioService {

    private static final Logger LOG = LoggerFactory.getLogger(NioService.class);


    //启动服务器
    public void start() throws IOException {
        //1.创建selector
        Selector selector = Selector.open();
        //2.创建channel,并且绑定端口,设置成非阻塞形式，
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //InetSocketAddress继承了SocketAddress
        serverSocketChannel.bind(new InetSocketAddress(9400));
        serverSocketChannel.configureBlocking(false);
        //3.将channel注册到selector上，监听连接事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        LOG.info("nio服务端启动成功，serverSocketAddress is {}", serverSocketChannel.getLocalAddress());
        //4.调用对应的方法，处理对应的逻辑
        //循环等待有新的客户端想要建立连接
        for (; ; ) {
            //可用的channel数量
            int readyChannel = selector.select();
            if (readyChannel == 0) {
                continue;
            }
            //获取可用的channel集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
            while (selectionKeyIterator.hasNext()) {
                SelectionKey next = selectionKeyIterator.next();
                selectionKeyIterator.remove();

                //接入事件
                if (next.isAcceptable()) {
                    acceptableHandler(serverSocketChannel, selector);
                }

                //可读事件
                if (next.isReadable()) {
                    readableHandler(next, selector);
                }
            }
        }
    }

    //接入事件处理（当该方法的数据获取不到时，可通过其他方法进行传值，获取到数据）
    private void acceptableHandler(ServerSocketChannel serverSocketChannel, Selector selector) throws IOException {
        //1.如果是接入事件，创建socketChannel
        SocketChannel socketChannel = serverSocketChannel.accept();
        //2.既然是channel,就得设置成非阻塞形式
        socketChannel.configureBlocking(false);
        //3.既然是channel,就要注册到selector上
        socketChannel.register(selector, SelectionKey.OP_READ);
        //4.给客户端ack
        socketChannel.write(StandardCharsets.UTF_8.encode("is not friends"));

    }

    //可读事件处理
    private void readableHandler(SelectionKey selectionKey, Selector selector) throws IOException {
        //1.从selectKey中获取到已经就绪的channel
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        //2.创建buffer，只用buffer才能创建channel的读和写
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //3.循环读取客户端请求信息
        StringBuilder request = new StringBuilder();
        while (socketChannel.read(byteBuffer) > 0) {
            //切换buffer为读模式
            byteBuffer.flip();
            String readByteBuffer = StandardCharsets.UTF_8.decode(byteBuffer).toString();
            request.append(readByteBuffer);


        }
        //4.将channel注册到selector上，注意监听的事件selectorKey
        socketChannel.register(selector, SelectionKey.OP_READ);
        //5.将客户端发送的请求信息广播给其他客户端
        if (StringUtils.isBlank(request)) {
            //广播给其他的客户端
            LOG.info("request is {}", request);
        }
    }


    public static void main(String[] args) throws IOException {
        new NioService().start();

    }
}
